import { BaseCrawlerEngine, ICrawlerEngine, EngineConfig, ValidationResult } from '@weubi/engines';
import { CrawlerTask, CrawlerResult, CrawlerEngine } from '@weubi/shared';
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import * as cheerio from 'cheerio';
import { JSDOM } from 'jsdom';
const UserAgent = require('user-agents');
import { logger } from '../utils/logger';

export class HttpEngine extends BaseCrawlerEngine implements ICrawlerEngine {
  readonly name: CrawlerEngine = 'http';
  readonly version = '1.0.0';
  readonly description = 'HTTP客户端引擎 - 轻量级网页抓取';

  private httpClient: AxiosInstance;
  private userAgent: InstanceType<typeof UserAgent>;

  constructor() {
    super();
    this.userAgent = new UserAgent();
    this.setupHttpClient();
  }

  protected async doInitialize(): Promise<void> {
    // HTTP引擎无需特殊初始化
    logger.info('✅ HTTP engine initialized');
  }

  protected async doExecute(task: CrawlerTask): Promise<CrawlerResult> {
    const startTime = Date.now();
    
    try {
      // 准备请求配置
      const requestConfig = this.buildRequestConfig(task);
      
      // 发送HTTP请求
      logger.info(`🌐 Fetching URL: ${task.url}`);
      const response = await this.httpClient.request(requestConfig);

      // 处理响应数据
      const extractedData = await this.extractData(response.data, task);

      return {
        success: true,
        data: extractedData,
        metadata: {
          engine: this.name,
          timestamp: new Date(),
          url: task.url,
          duration: Date.now() - startTime,
          statusCode: response.status,
        },
      };

    } catch (error) {
      logger.error(`❌ HTTP engine error for ${task.url}:`, error);
      
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown HTTP error',
        metadata: {
          engine: this.name,
          timestamp: new Date(),
          url: task.url,
          duration: Date.now() - startTime,
        },
      };
    }
  }

  protected async doCleanup(): Promise<void> {
    // HTTP引擎无需特殊清理
    logger.info('✅ HTTP engine cleaned up');
  }

  async isAvailable(): Promise<boolean> {
    return true; // HTTP引擎总是可用
  }

  getConfig(): EngineConfig {
    return {
      capabilities: {
        javascript: false,
        cookies: true,
        screenshots: false,
        pdf: false,
        proxy: true,
        userAgent: true,
        headers: true,
      },
      defaults: {
        timeout: 30000,
        retries: 3,
        delay: 1000,
        userAgent: this.userAgent.toString(),
      },
      limits: {
        maxConcurrency: 10,
        maxTimeout: 300000,
      },
    };
  }

  validateConfig(config: any): ValidationResult {
    const result = super.validateConfig(config);

    // HTTP引擎特定验证
    if (config.selectors && typeof config.selectors !== 'object') {
      result.errors.push('Selectors must be an object');
    }

    if (config.followRedirects !== undefined && typeof config.followRedirects !== 'boolean') {
      result.errors.push('followRedirects must be a boolean');
    }

    if (config.maxRedirects && (config.maxRedirects < 0 || config.maxRedirects > 10)) {
      result.errors.push('maxRedirects must be between 0 and 10');
    }

    return {
      valid: result.errors.length === 0,
      errors: result.errors,
      warnings: result.warnings,
    };
  }

  private setupHttpClient(): void {
    this.httpClient = axios.create({
      timeout: 30000,
      maxRedirects: 5,
      validateStatus: (status) => status < 500, // 接受所有非5xx状态码
      headers: {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Accept-Encoding': 'gzip, deflate',
        'DNT': '1',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
      },
    });

    // 请求拦截器
    this.httpClient.interceptors.request.use((config) => {
      // 设置随机User-Agent
      config.headers['User-Agent'] = this.userAgent.toString();
      return config;
    });

    // 响应拦截器
    this.httpClient.interceptors.response.use(
      (response) => response,
      (error) => {
        if (error.response) {
          logger.warn(`HTTP ${error.response.status}: ${error.response.statusText}`);
        }
        return Promise.reject(error);
      }
    );
  }

  private buildRequestConfig(task: CrawlerTask): AxiosRequestConfig {
    const config: AxiosRequestConfig = {
      url: task.url,
      method: 'GET',
      timeout: task.config.timeout || 30000,
      maxRedirects: task.config.maxRedirects || 5,
      headers: {
        ...task.config.headers,
      },
    };

    // 设置User-Agent
    if (task.config.userAgent) {
      config.headers = config.headers || {};
      config.headers['User-Agent'] = task.config.userAgent;
    }

    // 设置代理（如果配置了）
    if (task.config.proxy) {
      // 这里可以添加代理配置逻辑
    }

    return config;
  }

  private async extractData(html: string, task: CrawlerTask): Promise<any> {
    if (!task.config.selectors && !task.config.script) {
      // 如果没有配置选择器，返回原始HTML
      return { html: html.substring(0, 10000) }; // 限制长度
    }

    let extractedData: any = {};

    // 使用CSS选择器提取数据
    if (task.config.selectors) {
      extractedData = this.extractWithSelectors(html, task.config.selectors);
    }

    // 执行自定义脚本（在JSDOM环境中）
    if (task.config.script) {
      const scriptResult = await this.executeScript(html, task.config.script);
      extractedData = { ...extractedData, ...scriptResult };
    }

    return extractedData;
  }

  private extractWithSelectors(html: string, selectors: any): any {
    const $ = cheerio.load(html);
    const result: any = {};

    for (const [key, selector] of Object.entries(selectors)) {
      try {
        if (typeof selector === 'string') {
          // 简单选择器
          const element = $(selector);
          result[key] = element.length > 1 
            ? element.map((_, el) => $(el).text().trim()).get()
            : element.text().trim();
        } else if (typeof selector === 'object' && selector !== null) {
          // 复杂选择器配置
          const config = selector as any;
          const elements = $(config.selector);
          
          if (config.multiple) {
            result[key] = elements.map((_, el) => {
              const $el = $(el);
              return config.attribute 
                ? $el.attr(config.attribute)
                : $el.text().trim();
            }).get();
          } else {
            const $el = elements.first();
            result[key] = config.attribute 
              ? $el.attr(config.attribute)
              : $el.text().trim();
          }
        }
      } catch (error) {
        logger.warn(`⚠️ Failed to extract data for selector '${key}':`, error);
        result[key] = null;
      }
    }

    return result;
  }

  private async executeScript(html: string, script: string): Promise<any> {
    try {
      const dom = new JSDOM(html, {
        runScripts: 'outside-only',
        resources: 'usable',
      });

      const window = dom.window;
      const document = window.document;

      // 创建安全的执行环境
      const context = {
        document,
        window,
        $: cheerio.load(html),
        console: {
          log: (...args: any[]) => logger.info('Script log:', ...args),
          warn: (...args: any[]) => logger.warn('Script warn:', ...args),
          error: (...args: any[]) => logger.error('Script error:', ...args),
        },
      };

      // 执行脚本
      const func = new Function('context', `
        const { document, window, $, console } = context;
        ${script}
      `);

      const result = func(context);
      return result || {};

    } catch (error) {
      logger.error('❌ Script execution error:', error);
      return { scriptError: error instanceof Error ? error.message : String(error) };
    }
  }
}
